package com.cwx.mychat.login;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cwx.mychat.config.AppConfig;
import com.cwx.mychat.entity.constant.CodeConstant;
import com.cwx.mychat.entity.dto.ModelConfigDto;
import com.cwx.mychat.entity.dto.TokenUserInfoDto;
import com.cwx.mychat.entity.enums.ExceptionBizCodeEnum;
import com.cwx.mychat.entity.enums.UserStatusEnum;
import com.cwx.mychat.entity.po.AIConfig;
import com.cwx.mychat.entity.po.UserContact;
import com.cwx.mychat.entity.po.UserInfo;
import com.cwx.mychat.entity.po.UserInfoOther;
import com.cwx.mychat.entity.vo.UserInfoVO;
import com.cwx.mychat.exception.BusinessException;
import com.cwx.mychat.login.authentication.UsernameAuthentication;
import com.cwx.mychat.mappers.AIConfigMapper;
import com.cwx.mychat.mappers.UserInfoMapper;
import com.cwx.mychat.mappers.UserInfoOtherMapper;
import com.cwx.mychat.service.UserContactService;
import com.cwx.mychat.utils.R;
import com.cwx.mychat.utils.jwt.JwtUtils;
import com.cwx.mychat.utils.redis.RedisComponent;
import com.cwx.mychat.utils.redis.RedisUtil;
import com.cwx.mychat.utils.stringUtils.StringUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AbstractAuthenticationTargetUrlRequestHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 作者： cwx
 * 时间： 2024/10/19 0:21
 * 版本： 1.0
 * 注释：登陆成功的处理逻辑
 */
@Slf4j
@Component
public class LoginSuccessHandler extends AbstractAuthenticationTargetUrlRequestHandler implements AuthenticationSuccessHandler {


    @Autowired
    private AppConfig appConfig;

    @Resource
    private RedisUtil redisUtil;

    @Autowired
    private RedisComponent redisComponent;

    @Autowired
    private UserContactService userContactService;
    @Autowired
    private UserInfoOtherMapper otherMapper;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private AIConfigMapper aiConfigMapper;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {

        log.info("恭喜登录成功...");
        if(authentication == null){
            throw new RuntimeException(ExceptionBizCodeEnum.LOGIN_VERIFICATION_FAILED.getMsg());
        }
        Object principal = authentication.getPrincipal();
        if(!(principal instanceof UserInfo)){
            throw new RuntimeException("认证成功后无法得到UserInfo对象");
        }
        UserInfoVO userInfoVO = new UserInfoVO();
        UserInfo userInfo = (UserInfo) authentication.getPrincipal();
        if(UserStatusEnum.DISABLE.getStatus().equals(userInfo.getStatus())){
            //账号禁用
            throw new RuntimeException(ExceptionBizCodeEnum.ACCOUNT_STOP_EXCEPTION.getMsg());
        }
        //将tokenUserInfoDto存入Redis中
        TokenUserInfoDto tokenUserInfoDto = getTokenUserInfoDto(userInfo);
        String token = JwtUtils.createJWT(tokenUserInfoDto.getUserId());
        tokenUserInfoDto.setToken(token);
        redisComponent.saveTokenUserInfoDto(tokenUserInfoDto);
        //将联系人群聊信息存入Redis中
        // 1.查询好友
        // 1.2 判定谁加的谁好友
        List<UserContact> userContactList = userContactService.selectContact(userInfo);
        List<String> contactIdList = userContactList.stream().map(UserContact::getContactId).collect(Collectors.toList());
        // 2.存入Redis中,先删除，后增添
        redisComponent.removeUserContactBatch(userInfo.getUserId());
        if(!contactIdList.isEmpty()){
            redisComponent.saveUserContactBatch(userInfo.getUserId(), contactIdList);
        }
        //将数据全部整合到userInfoVo中
        BeanUtils.copyProperties(userInfo, userInfoVO);
        userInfoVO.setToken(tokenUserInfoDto.getToken());
        //查询用户其他信息
        UserInfoOther userInfoOther = otherMapper.selectOne(new LambdaQueryWrapper<UserInfoOther>().eq(UserInfoOther::getUserId, userInfo.getUserId()));
        userInfoVO.setUserInfoOther(userInfoOther);
        //查询用户的AI模型信息
        List<AIConfig> aiConfigs = aiConfigMapper.selectListByUserIdEnable(userInfo.getUserId());
        // 设置机器人信息
        if(aiConfigs != null){
            setAIConfigInfo(aiConfigs);
        }
        //更新登录时间
        UserInfo lastLoginTime = new UserInfo();
        lastLoginTime.setLastLoginTime(new Date());
        lastLoginTime.setUserId(userInfo.getUserId());
        userInfoMapper.updateById(lastLoginTime);
        //返回登录信息
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        PrintWriter writer = response.getWriter();
        R put = R.ok().put(CodeConstant.RESULT_MSG, userInfoVO);
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonResponse = objectMapper.writeValueAsString(put);
        writer.write(jsonResponse);
        writer.flush();
        writer.close();
    }

    private TokenUserInfoDto getTokenUserInfoDto(UserInfo userInfo){
        TokenUserInfoDto tokenUserInfoDto = new TokenUserInfoDto();
        tokenUserInfoDto.setUserId(userInfo.getUserId());
        tokenUserInfoDto.setNickName(userInfo.getNickName());
        tokenUserInfoDto.setAvatar(userInfo.getUserAvatar());
        String adminEmail = appConfig.getAdminEmail();
        tokenUserInfoDto.setAdmin(!StringUtil.isEmpty(adminEmail) && ArrayUtils.contains(adminEmail.split(","), userInfo.getEmail()));
        return tokenUserInfoDto;
    }

    //设置AIConfig信息
    private void setAIConfigInfo(List<AIConfig> aiConfigs){
        ModelConfigDto modelConfigDto = new ModelConfigDto();
        AIConfig aiConfig = aiConfigs.get(0);
        //判断aiConfigs是否大于1
        if(aiConfigs.size() > 1){
            //获取除了第一个外的其他
            List<Integer> aiListIds = aiConfigs.subList(1, aiConfigs.size()).stream().map(AIConfig::getAiId).toList();
            //将其enable值都改为0
            aiConfigMapper.updateBatchEnableById(aiListIds);
        }
        //将其存在Redis中
        BeanUtils.copyProperties(aiConfig, modelConfigDto);
        aiConfig.getModel().stream().filter(model -> model.enable() == 1)
                .findFirst()
                .ifPresent(model1 -> modelConfigDto.setAiModel(model1.modelName()));
        boolean set = redisUtil.set(CodeConstant.REDIS_ROBOT_INFO, modelConfigDto);
        if(!set){
            log.error("设置机器人信息失败");
        }
    }

}
